package com.right.factory;

import ch.qos.logback.core.encoder.ByteArrayUtil;
import com.right.util.ByteUtil;
import com.right.util.Crc16;

import java.util.Objects;

/**********************************************
 * @author pillar
 * @date 2018/3/22
 * 发送和接收数据包
 **********************************************/
public class CloudPackage {
    /**
     * 起始符，固定为0xFF,0xFF
     */
   private byte[] startBytes = {(byte) 0xFF, (byte) 0xFF};
    /**
     * 数据单元长度（校验码）
     * 内容长度+协议类型+序列号+时间日期+内容
     */
    private byte[] lenBytes = new byte[2];
    /**
     * 内容长度
     */
    private byte contentLen;
    /**
     * 协议类型
     *
     */
   private byte command;
    /**
     * 序列号
     * 从系统上电开机为 0,所有信息依次累加
     */
   private byte[] serilByte= new byte[2];
    /**
     * 时间
     */
   private byte[] time = new byte[6];
    /**
     * 内容
     */
   private byte[] dataBytes;
    /**
     * 结束标志
     */
   private byte[] endBytes = {0x0D,0x0A};
    /**
     * 检查报文的合法性
     * @param packageData
     * @return
     */
    boolean checkPackage(byte[] packageData) {
        return !(packageData[0] != startBytes[0]
                || packageData[1] != startBytes[1])
                && rightCommand(packageData[5])
                && checkedBit(packageData);
    }

    /**
     * 检查校验码是否正确
     * @param packageData
     * @return
     */
    private boolean checkedBit(byte[] packageData) {
        System.arraycopy(packageData,2,lenBytes,0,lenBytes.length);
        return Objects.equals(ByteArrayUtil.toHexString(lenBytes), ByteArrayUtil.toHexString(ByteUtil.intToByte(getCheckBit(packageData,4))));
    }

    /**
     * 是否合法指令
     * @param csCommand
     * @return
     */
    private boolean rightCommand(byte csCommand) {
        switch (csCommand){
            default:
                return true;
        }
    }

    /**
     * 解析报文
     * @param packageData
     * @return
     */
    CloudPackage parse(byte[] packageData){
        setContentLen(packageData[4]);
        setCommand(packageData[5]);
        System.arraycopy(packageData,6,serilByte,0,serilByte.length);
        System.arraycopy(packageData,8,time,0,time.length);
        byte[] data = new byte[getContentLen() & 0xFF];
        System.arraycopy(packageData,14,data,0,data.length);
        setDataBytes(data);
       return this;
   }

   public void setSerilByte(int len){
        this.serilByte = ByteUtil.intToByteCompose(len);
   }
    public byte getCommand() {
        return command;
    }

    public byte getContentLen() {
        return contentLen;
    }

    public void setContentLen(byte contentLen) {
        this.contentLen = contentLen;
    }

    public void setCommand(byte command) {
        this.command = command;
    }

    public byte[] getDataBytes() {
        return dataBytes;
    }

    public void setDataBytes(byte[] dataBytes) {
        this.dataBytes = dataBytes;
        setContentLen((byte) dataBytes.length);
    }

    /**
     * 组装发送报文
     * @return
     */
    public byte[] composeSendData(){
        byte[] packageData = new byte[16 + dataBytes.length];
        packageData[0] = startBytes[0];
        packageData[1] = startBytes[1];
        packageData[4] = getContentLen();
        packageData[5] = getCommand();
        System.arraycopy(serilByte,0,packageData,6,serilByte.length);
        System.arraycopy(time,0,packageData,8,time.length);
        System.arraycopy(dataBytes,0,packageData,14,dataBytes.length);
        packageData[packageData.length - 2] = endBytes[0];
        packageData[packageData.length - 1] = endBytes[1];
        byte[] checkedByte = ByteUtil.intToByteCompose(getCheckBit(packageData,6));
        System.arraycopy(checkedByte,0,packageData,2,checkedByte.length);
       return packageData;
    }



    /**
     * 计算校验位
     * @param packageData
     * @return
     */
    private int getCheckBit(byte[] packageData,int ignoreLen) {
        byte[] checkBytes = new byte[packageData.length - ignoreLen];
        System.arraycopy(packageData,4,checkBytes,0,checkBytes.length);
        return Crc16.createCrc(checkBytes);
    }


    public void setTime(byte[] time) {
        this.time = time;
    }
}
